package com.example.aspect;

import com.example.annotation.Loggable;
import com.example.annotation.PerformanceMonitor;
import com.example.annotation.RequiresPermission;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Set;

/**
 * 基于注解的切面类 - 这才是实际项目中常用的方式！
 * 
 * 与硬编码切点表达式相比，基于注解的方式有以下优势：
 * 1. 更灵活：可以精确控制哪些方法需要AOP
 * 2. 更清晰：在方法上直接看到要应用的横切关注点
 * 3. 更可配置：可以通过注解参数传递配置信息
 * 4. 更易维护：不需要修改切面代码，只需要加减注解
 */
@Aspect
@Component
public class AnnotationBasedAspect {

    // 模拟当前用户权限
    private static final Set<String> CURRENT_USER_PERMISSIONS = Set.of("USER_CREATE", "USER_READ", "USER_UPDATE");

    /**
     * 基于@Loggable注解的切点
     * 
     * @annotation(loggable) 表示匹配带有@Loggable注解的方法
     * 并且可以将注解实例注入到通知方法中
     */
    @Around("@annotation(loggable)")
    public Object handleLoggable(ProceedingJoinPoint joinPoint, Loggable loggable) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        
        // 根据注解配置决定是否记录参数
        if (loggable.logArgs()) {
            System.out.println("📝 [" + loggable.level() + "] 调用方法: " + methodName);
            System.out.println("📝 [" + loggable.level() + "] 参数: " + Arrays.toString(joinPoint.getArgs()));
        }
        
        // 如果有自定义消息，显示它
        if (!loggable.message().isEmpty()) {
            System.out.println("📝 [" + loggable.level() + "] " + loggable.message());
        }
        
        try {
            Object result = joinPoint.proceed();
            
            // 根据注解配置决定是否记录返回值
            if (loggable.logResult()) {
                System.out.println("📝 [" + loggable.level() + "] 返回值: " + result);
            }
            
            return result;
        } catch (Exception e) {
            System.out.println("📝 [ERROR] 方法执行异常: " + e.getMessage());
            throw e;
        }
    }

    /**
     * 基于@PerformanceMonitor注解的性能监控
     */
    @Around("@annotation(monitor)")
    public Object handlePerformanceMonitor(ProceedingJoinPoint joinPoint, PerformanceMonitor monitor) throws Throwable {
        long startTime = System.currentTimeMillis();
        String methodName = joinPoint.getSignature().getName();
        
        if (monitor.detailed()) {
            System.out.println("⏱️ [性能监控] 开始执行: " + methodName);
        }
        
        try {
            Object result = joinPoint.proceed();
            
            long duration = System.currentTimeMillis() - startTime;
            
            // 检查是否超过阈值
            if (duration > monitor.threshold()) {
                System.out.println("⚠️ [性能警告] 方法 " + methodName + " 执行时间 " + duration + "ms 超过阈值 " + monitor.threshold() + "ms");
            } else if (monitor.detailed()) {
                System.out.println("✅ [性能监控] 方法 " + methodName + " 执行时间: " + duration + "ms");
            }
            
            return result;
        } catch (Exception e) {
            long duration = System.currentTimeMillis() - startTime;
            System.out.println("❌ [性能监控] 方法 " + methodName + " 执行异常，耗时: " + duration + "ms");
            throw e;
        }
    }

    /**
     * 基于@RequiresPermission注解的权限验证
     * 
     * 这里演示了前置通知的使用
     */
    @Before("@annotation(permission)")
    public void handlePermissionCheck(JoinPoint joinPoint, RequiresPermission permission) {
        String methodName = joinPoint.getSignature().getName();
        String[] requiredPermissions = permission.value();
        
        System.out.println("🔐 [权限检查] 验证方法 " + methodName + " 的权限");
        System.out.println("🔐 [权限检查] 需要权限: " + Arrays.toString(requiredPermissions));
        
        boolean hasPermission = false;
        
        if (permission.mode() == RequiresPermission.Mode.ALL) {
            // 需要所有权限
            hasPermission = CURRENT_USER_PERMISSIONS.containsAll(Arrays.asList(requiredPermissions));
        } else {
            // 需要任一权限
            hasPermission = Arrays.stream(requiredPermissions)
                    .anyMatch(CURRENT_USER_PERMISSIONS::contains);
        }
        
        if (!hasPermission) {
            System.out.println("❌ [权限检查] 权限不足，拒绝访问！");
            throw new SecurityException("权限不足：需要权限 " + Arrays.toString(requiredPermissions));
        }
        
        System.out.println("✅ [权限检查] 权限验证通过");
    }

    /**
     * 组合注解的处理 - 当一个方法有多个注解时
     * 
     * 这个切点匹配同时带有@Loggable和@PerformanceMonitor注解的方法
     */
    @Around("@annotation(com.example.annotation.Loggable) && @annotation(com.example.annotation.PerformanceMonitor)")
    public Object handleCombinedAnnotations(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("🎯 [组合注解] 检测到方法同时具有日志和性能监控注解: " + joinPoint.getSignature().getName());
        
        // 这里可以添加特殊的组合逻辑
        return joinPoint.proceed();
    }

    /**
     * 通用方法：获取方法上的注解
     */
    private <T extends java.lang.annotation.Annotation> T getMethodAnnotation(JoinPoint joinPoint, Class<T> annotationClass) {
        try {
            Method method = ((org.aspectj.lang.reflect.MethodSignature) joinPoint.getSignature()).getMethod();
            return method.getAnnotation(annotationClass);
        } catch (Exception e) {
            return null;
        }
    }
} 